/*
 Big Two for Game Gardens - a Chinese climbing-style card game
 Copyright (C) 2005 Chris Nokleberg

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

 Linking this library statically or dynamically with other modules is
 making a combined work based on this library.  Thus, the terms and
 conditions of the GNU General Public License cover the whole
 combination.
 */

package cribbage.server;

import com.samskivert.util.Interval;
import com.threerings.crowd.server.PlaceManager;
import com.threerings.parlor.card.data.*;
import com.threerings.parlor.card.server.CardGameManager;

import com.threerings.parlor.turn.server.TurnGameManager;
import com.threerings.parlor.turn.server.TurnGameManagerDelegate;
import com.threerings.presents.dobj.MessageEvent;
import com.threerings.presents.server.PresentsServer;
import com.threerings.util.MessageBundle;

import cribbage.data.CribbageCodes;
import cribbage.data.CribbageObject;

public class CribbageManager extends CardGameManager implements TurnGameManager, CribbageCodes {
   private CribbageObject _obj;

   private Hand [] _hands;

   private int [] scores;

   private TurnGameManagerDelegate _delegate;

   private Deck _deck;

   private long _timeTurnStarted;

   private int numTurnsInPhase;

   public CribbageManager () {
      addDelegate(_delegate = new TurnGameManagerDelegate(this));
      numTurnsInPhase = 0;
   }

   @SuppressWarnings("unchecked")
   @Override
   protected Class getPlaceObjectClass () {
      return CribbageObject.class;
   }

   @Override
   public void didInit () {
      super.didInit();
      registerMessageHandler(CribbageCodes.PLAY_REQUEST, new MessageHandler() {
         public void handleEvent (MessageEvent event, PlaceManager pmgr) {
            if (_playerOids[_delegate.getTurnHolderIndex()] == event.getSourceOid())
               handlePlayRequest((Card []) event.getArgs()[0]);
         }
      });
   }

   @SuppressWarnings("unchecked")
   private void handlePlayRequest (Card [] hand) {
      int pidx = _delegate.getTurnHolderIndex();

      System.out.print(_obj.players[pidx]+": play request for ");
      for (Card c : hand) {
         System.out.print(c + " ");
      }
      System.out.println("from hand "+_hands[pidx]);

      if (_hands[pidx].containsAll(hand)) {
         _hands[pidx].removeAll(hand);
         System.out.println("Setting hand size for "+_obj.players[pidx]+" to "+_hands[pidx].size());
         _obj.startTransaction();
         _obj.setOwner(pidx);
         _obj.setHandSize(pidx, _hands[pidx].size());
         _obj.commitTransaction();
         if (scores[pidx] > 120) {
            endGame();
         } else {
            endTurnWithDelay(500);
         }
      } else {
         System.err.println("Warning: " + _obj.players[pidx] + " tried to play invalid hand "
               + hand);
      }
   }

   @Override
   protected void assignWinners (boolean [] winners) {}

   private void endTurnWithDelay (long min) {
      long elapsed = System.currentTimeMillis() - _timeTurnStarted;
      if (elapsed >= min) {
         _delegate.endTurn();
      } else {
         (new Interval(PresentsServer.omgr) {
            public void expired () {
               _delegate.endTurn();
            }
         }).schedule(min - elapsed);
      }
   }

   @Override
   public void didStartup () {
      super.didStartup();
      _obj = (CribbageObject) _gameobj;
   }

   @Override
   protected void gameWillStart () {
      super.gameWillStart();

      System.out.println("Game starting, dealing hands.");

      _deck = new Deck();
      _deck.shuffle();
      _hands = dealHands(_deck, 6);

      scores = new int [getPlayerCount()];

      _obj.startTransaction();
      _obj.setOwner(-1);
      _obj.setWinners(new boolean [2]);
      _obj.setHandSizes(new int [] {6, 6, 40, 0}); // array contains sizes of
      // hand 1, hand 2, deck, crib
      _obj.setTurnPhase(MAKE_CRIB);
      _obj.commitTransaction();
   }

   @Override
   public void turnWillStart () {
      super.turnWillStart();

      if (_obj.turnPhase == MAKE_CRIB) {
         if (numTurnsInPhase == getPlayerCount()) {
            _obj.setTurnPhase(NORMAL_PLAY);
            numTurnsInPhase = 0;
         } else
            numTurnsInPhase++;
      } else if (_obj.turnPhase == NORMAL_PLAY) {
         int [] sizes = _obj.getHandSizes();
         if (sizes[0] + sizes[1] == 0)
            _obj.setTurnPhase(SCORING);
      } else if (_obj.turnPhase == SCORING) {
         if (numTurnsInPhase == getPlayerCount()) {
            resetGame();
         } else
            numTurnsInPhase++;
      }
   }

   @Override
   protected void gameDidStart () {
      super.gameDidStart();
      _obj.setUpCard((Card) (_deck.get(_deck.size() - 1)));
   }

   @Override
   protected void gameDidEnd () {
      super.gameDidEnd();
      int winnerIndex = _obj.getWinnerIndex();
      if (winnerIndex >= 0) {
         systemMessage(CribbageCodes.CRIBBAGE_MSG_BUNDLE, MessageBundle.tcompose("m.won_the_game",
               _obj.players[winnerIndex]));
      }
      (new Interval(PresentsServer.omgr) {
         public void expired () {
            if (_gameobj.isActive() && _gameobj.getActivePlayerCount() == 4)
               startGame();
         }
      }).schedule(3000L);
   }
}
